package com.yyr.callmessage.core.util;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.reflect.TypeToken;
import lombok.extern.slf4j.Slf4j;
import okhttp3.*;
import org.apache.http.NameValuePair;
import org.apache.http.client.utils.URLEncodedUtils;
import org.apache.http.message.BasicNameValuePair;
import org.apache.logging.log4j.util.Strings;
import org.springframework.util.CollectionUtils;

import java.lang.reflect.Type;
import java.net.HttpURLConnection;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.concurrent.TimeUnit;

@Slf4j
public class HttpUtil {

	public static final String HttpMethodGet = "GET";
	public static final String HttpMethodPost = "POST";

	//********************************application/json**************************************************
	public static <T> T postJson(String url, Object requestObject, Type responseType) {
		return requestJson(url, HttpMethodPost, null, requestObject, responseType, null);
	}
	
	public static <T> T postJson(String url, Object requestObject, Class<T> responseClass) {
		return requestJson(url, HttpMethodPost, null, requestObject, responseClass, null);
	}
	
	public static <T> T postJson(String url, Object urlParams, Object requestObject, Type responseType, Map<String, String> headers) {
		return requestJson(url, HttpMethodPost, urlParams, requestObject, responseType, headers);
	}
	
	public static <T> T getJson(String url, Object urlParams, Type responseType) {
		return requestJson(url, HttpMethodGet, urlParams, null, responseType, null);
	}
	
	public static <T> T getJson(String url, Object urlParams, Class<T> responseClass) {
		return requestJson(url, HttpMethodGet, urlParams, null, responseClass, null);
	}

	public static <T> T getJson(String url, Object urlParams, Type responseType, Map<String, String> headers) {
		return requestJson(url, HttpMethodGet, urlParams, null, responseType, headers);
	}

	//封装请求
	public static <T> T requestJson(String url, String requestMethod, Object /*请求参数*/urlParams, Object requestObject, Type responseType, Map<String, String> headers) {
		// headers
		if (headers == null) {
			headers = new HashMap<>();
		}
		headers.put("Content-Type", "application/json");
		headers.put("Accept", "application/json");

		// url params   请求参数
		Map<String, String> urlParamsMap = null;
		if (urlParams != null) {
			Gson gson = new GsonBuilder().create();
			urlParamsMap = gson.fromJson(gson.toJson(urlParams), new TypeToken<Map<String, String>>() {}.getType());
		}

		// body
		Gson gson = new GsonBuilder().create();
		String requestBody = null;
		if (requestObject != null) {
			requestBody = gson.toJson(requestObject);
		}

		// response
		String responseJson = request(url, urlParamsMap, requestBody, requestMethod, headers);
		return gson.fromJson(responseJson, responseType);
	}

	//********************************x-wwww-form-urlencoded**************************************************

	public static <T> T postJsonByWWWUrlEncoded(String url, Object urlParams, Object requestObject, Type responseType, Map<String, String> headers) {

		return requestJsonByWWWUrlEncoded(url, HttpMethodPost, urlParams, requestObject, responseType, headers);
	}

	public static <T> T getJsonByWWWUrlEncoded(String url, Object urlParams, Object requestObject, Type responseType, Map<String, String> headers) {
		return requestJsonByWWWUrlEncoded(url, HttpMethodGet, urlParams, requestObject, responseType, headers);
	}

	private static <T> T requestJsonByWWWUrlEncoded(String url, String requestMethod, Object urlParams, Object requestObject, Type responseType, Map<String, String> headers) {
		// headers
		if (headers == null) {
			headers = new HashMap<>();
		}
		//表单提交，表单上传的编码格式： key=value&key=value
		//Content-Type: 发送端（客户端、服务端）发送的实体数据类型
		headers.put("Content-Type", "application/x-www-form-urlencoded");
		//Accept : 客户端想要接收的数据类型
		headers.put("Accept", "application/json");

		// url params
		Map<String, String> urlParamsMap = null;
		if (urlParams != null) {
			Gson gson = new GsonBuilder().create();
			urlParamsMap = gson.fromJson(gson.toJson(urlParams), new TypeToken<Map<String, String>>() {}.getType());
		}

		// body
		String requestBody = null;
		if (requestObject != null) {
			Gson gson = new GsonBuilder().create();
			Map<String, String> requestMap = gson.fromJson(gson.toJson(requestObject), new TypeToken<Map<String, String>>() {}.getType());
			if (requestMap != null && !requestMap.isEmpty()) {
				List<NameValuePair> requestPairList = new ArrayList<>(requestMap.size());
				Iterator it = requestMap.entrySet().iterator();
				while(it.hasNext()) {
					Map.Entry entry = (Map.Entry)it.next();
					requestPairList.add(new BasicNameValuePair(entry.getKey().toString(), entry.getValue().toString()));
				}

				requestBody = URLEncodedUtils.format(requestPairList, StandardCharsets.UTF_8);
			}
		}

		// response
		String responseJson = request(url, urlParamsMap, requestBody, requestMethod, headers);
		Gson gson = new GsonBuilder().create();
		return gson.fromJson(responseJson, responseType);
	}

	//********************************request**************************************************
	private static final OkHttpClient normalClient;
	static {
		normalClient = new OkHttpClient.Builder()
				.connectTimeout(10, TimeUnit.SECONDS)
				.writeTimeout(30, TimeUnit.SECONDS)
				.readTimeout(30, TimeUnit.SECONDS)
				.build();
	}

	public static String request(String url, Map<String, String> urlParams, String requestBodyStr, String requestMethod, Map<String, String> headers) {
		return request(url, urlParams, requestBodyStr, requestMethod, headers, normalClient);
	}

	public static String request(String url, Map<String, String> urlParams, String requestBodyStr, String requestMethod, Map<String, String> headers, OkHttpClient okHttpClient) {
		// url后面参数
		if (urlParams != null && urlParams.size() > 0) {
			StringBuilder urlBuilder = new StringBuilder(url);
			urlBuilder.append("?");
			for (Map.Entry<String, String> params : urlParams.entrySet()) {
				urlBuilder.append(params.getKey()).append("=").append(params.getValue()).append("&");
			}

			url = urlBuilder.substring(0, urlBuilder.length() - 1);
		}

		MediaType contentType = MediaType.parse(headers.get("Content-Type"));
		RequestBody body = null;
		if (Strings.isNotBlank(requestBodyStr) && !requestMethod.equalsIgnoreCase(HttpMethodGet)) {
			body = RequestBody.create(contentType, requestBodyStr);
		}
		Request.Builder requestBuilder = new Request.Builder().url(url);
		if (!CollectionUtils.isEmpty(headers)) {
			headers.forEach((k, v) -> requestBuilder.addHeader(k, v));
		}

		Request request = requestBuilder.method(requestMethod, body).build();
		ResponseBody responseBody = null;
		String result = null;
		try {
//			log.info("request:{}\nbody:{}",  request.toString(), requestBodyStr);
			Response response = okHttpClient.newCall(request).execute();
			responseBody = response.body();
			if (response.code() == HttpURLConnection.HTTP_OK) {
				if (responseBody != null) {
					result = responseBody.string();
				}
			} else {
				throw new Exception(response.code() + "");
			}
		} catch (Exception e) {
			log.error("request url:{}, body:{}, error:{}", url, requestBodyStr, e.getMessage());
			e.printStackTrace();
			if(responseBody != null){
				responseBody.close();
			}
		}

		return result;
	}

}
